`timescale 1ns/100ps

module cm_fft3_N3 #(
    parameter C_DATA_WITH = 16 // 数据位宽
)(
    input  wire                     I_sys_clk,       // 工作时钟 100M
    input  wire                     I_data_start,    // 数据开始进入标志，与第一个数据对齐输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real,  // 数据输入（实部），从start开始连续输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag,  // 数据输入（虚部），从start开始连续输入
    output wire                     O_data_start,    // 数据开始输出标志与第一个数据对齐输出
    output reg  [C_DATA_WITH+1:0]   O_data_out_real, // 数据输出（实部），从start开始连续输出
    output reg  [C_DATA_WITH+1:0]   O_data_out_imag  // 数据输出（虚部），从start开始连续输出
);

// ============================================================
// 内部参数
// ============================================================
/// W03=1
/// W13=-0.5-0.866*j
/// W23=-0.5+0.866*j

// ============================================================
// 变量声明
// ============================================================

// 数据启动延迟寄存器
reg                     S_data_start_d1;
reg                     S_data_start_d2;
reg                     S_data_start_d3;
reg                     S_data_start_d4;
reg                     S_data_start_d5;
reg                     S_data_start_d6;
reg                     S_data_start_d7;
reg                     S_data_start_d8;
reg                     S_data_start_d9;

// 输入数据缓存
reg  [C_DATA_WITH-1:0]  S_data_in_real_d1;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d2;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d3;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d4;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d5;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d6;
reg  [C_DATA_WITH-1:0]  S_data_in_real_d7;

reg  [C_DATA_WITH-1:0]  S_data_in_imag_d1;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d2;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d3;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d4;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d5;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d6;
reg  [C_DATA_WITH-1:0]  S_data_in_imag_d7;

// 数据累加寄存器
reg  [C_DATA_WITH+1:0]  S_data_add_real;     // p0 add
reg  [C_DATA_WITH+1:0]  S_data_add_imag;     // p0 add

wire [11:0]             S_data_bi_p1;
wire [11:0]             S_data_bi_p2;

reg  [C_DATA_WITH+1:0]  S_data_add_real_p1;  // p1 add
reg  [C_DATA_WITH+1:0]  S_data_add_imag_p1;  // p1 add

reg  [C_DATA_WITH+1:0]  S_data_add_real_p2;  // p2 add
reg  [C_DATA_WITH+1:0]  S_data_add_imag_p2;  // p2 add

wire [C_DATA_WITH+12:0] S_data_multp2_real;
wire [C_DATA_WITH+12:0] S_data_multp2_imag;
wire [C_DATA_WITH+12:0] S_data_multp1_real;
wire [C_DATA_WITH+12:0] S_data_multp1_imag;

// ============================================================
// 主逻辑代码
// ============================================================

// 同步输入的 start 标志
always @(posedge I_sys_clk) begin
    S_data_start_d1 <= I_data_start;
    S_data_start_d2 <= S_data_start_d1;
    S_data_start_d3 <= S_data_start_d2;
    S_data_start_d4 <= S_data_start_d3;
    S_data_start_d5 <= S_data_start_d4;
    S_data_start_d6 <= S_data_start_d5;
    S_data_start_d7 <= S_data_start_d6;
    S_data_start_d8 <= S_data_start_d7;
    S_data_start_d9 <= S_data_start_d8;
end

// 缓存输入数据
always @(posedge I_sys_clk) begin
    S_data_in_real_d1 <= I_data_in_real;
    S_data_in_real_d2 <= S_data_in_real_d1;
    S_data_in_real_d3 <= S_data_in_real_d2;
    S_data_in_real_d4 <= S_data_in_real_d3;
    S_data_in_real_d5 <= S_data_in_real_d4;
    S_data_in_real_d6 <= S_data_in_real_d5;
    S_data_in_real_d7 <= S_data_in_real_d6;

    S_data_in_imag_d1 <= I_data_in_imag;
    S_data_in_imag_d2 <= S_data_in_imag_d1;
    S_data_in_imag_d3 <= S_data_in_imag_d2;
    S_data_in_imag_d4 <= S_data_in_imag_d3;
    S_data_in_imag_d5 <= S_data_in_imag_d4;
    S_data_in_imag_d6 <= S_data_in_imag_d5;
    S_data_in_imag_d7 <= S_data_in_imag_d6;
end

// 累加逻辑：p0
always @(posedge I_sys_clk) begin
    if (S_data_start_d5) begin
        S_data_add_real <= {{2{S_data_in_real_d5[C_DATA_WITH-1]}}, S_data_in_real_d5};
        S_data_add_imag <= {{2{S_data_in_imag_d5[C_DATA_WITH-1]}}, S_data_in_imag_d5};
    end else begin
        S_data_add_real <= S_data_add_real + {{2{S_data_in_real_d5[C_DATA_WITH-1]}}, S_data_in_real_d5};
        S_data_add_imag <= S_data_add_imag + {{2{S_data_in_imag_d5[C_DATA_WITH-1]}}, S_data_in_imag_d5};
    end
end

// 计算 p1 的旋转因子
assign S_data_bi_p1 = S_data_start_d1 ? -12'd887 : 12'd887;

// 调用复乘模块：p1
cmult #(
    .AWIDTH(C_DATA_WITH),
    .BWIDTH(12)
) u0_cmult (
    .clk(I_sys_clk),
    .ar(I_data_in_real),
    .ai(I_data_in_imag),
    .br(-12'd512),
    .bi(S_data_bi_p1),
    .pr(S_data_multp1_real),
    .pi(S_data_multp1_imag)
);

// 累加逻辑：p1
always @(posedge I_sys_clk) begin
    if (S_data_start_d6) begin
        S_data_add_real_p1 <= {{2{S_data_in_real_d6[C_DATA_WITH-1]}}, S_data_in_real_d6};
        S_data_add_imag_p1 <= {{2{S_data_in_imag_d6[C_DATA_WITH-1]}}, S_data_in_imag_d6};
    end else begin
        S_data_add_real_p1 <= S_data_add_real_p1 + S_data_multp1_real[(11+C_DATA_WITH):10] + S_data_multp1_real[9];
        S_data_add_imag_p1 <= S_data_add_imag_p1 + S_data_multp1_imag[(11+C_DATA_WITH):10] + S_data_multp1_imag[9];
    end
end

// 计算 p2 的旋转因子
assign S_data_bi_p2 = S_data_start_d2 ? 12'd887 : -12'd887;

// 调用复乘模块：p2
cmult #(
    .AWIDTH(C_DATA_WITH),
    .BWIDTH(12)
) u1_cmult (
    .clk(I_sys_clk),
    .ar(S_data_in_real_d1),
    .ai(S_data_in_imag_d1),
    .br(-12'd512),
    .bi(S_data_bi_p2),
    .pr(S_data_multp2_real),
    .pi(S_data_multp2_imag)
);

// 累加逻辑：p2
always @(posedge I_sys_clk) begin
    if (S_data_start_d7) begin
        S_data_add_real_p2 <= {{2{S_data_in_real_d7[C_DATA_WITH-1]}}, S_data_in_real_d7};
        S_data_add_imag_p2 <= {{2{S_data_in_imag_d7[C_DATA_WITH-1]}}, S_data_in_imag_d7};
    end else begin
        S_data_add_real_p2 <= S_data_add_real_p2 + S_data_multp2_real[(11+C_DATA_WITH):10] + S_data_multp2_real[9];
        S_data_add_imag_p2 <= S_data_add_imag_p2 + S_data_multp2_imag[(11+C_DATA_WITH):10] + S_data_multp2_imag[9];
    end
end

// 输出选择逻辑
always @(posedge I_sys_clk) begin
    if (S_data_start_d8) begin
        // p0
        O_data_out_real <= S_data_add_real;
        O_data_out_imag <= S_data_add_imag;
    end else if (S_data_start_d9) begin
        // p1
        O_data_out_real <= S_data_add_real_p1;
        O_data_out_imag <= S_data_add_imag_p1;
    end else begin
        // p2
        O_data_out_real <= S_data_add_real_p2;
        O_data_out_imag <= S_data_add_imag_p2;
    end
end

// 输出 start 标志
assign O_data_start = S_data_start_d9;

endmodule